﻿using AutoMapper;
using Microsoft.EntityFrameworkCore;
using QMERP.Domain.Dtos;
using QMERP.Domain.Entities;
using QMERP.Domain.Enums;
using QMERP.Infrastructure.CustomException;
using QMERP.Infrastructure.EFCore;
using QMERP.Infrastructure.EFCore.Extensions;
using QMERP.Infrastructure.Extensions;
using System.Data;

namespace QMERP.Application.Services
{
    public class StockService : IStockService
    {
        private readonly IMapper _mapper;
        private readonly QMERPDbContext _db;
        private IServiceProvider _serviceProvider;
        public StockService(IMapper mapper, QMERPDbContext db ,IServiceProvider serviceProvider)
        {
            _mapper = mapper;
            _db = db;
            _serviceProvider = serviceProvider;
        }
        /// <summary>
        /// 库存管理窗体
        /// </summary>
        /// <returns></returns>
        public async Task<PageResponse<StockResponse>> Query(PageRequest<StockRequest> request)
        {
            var response = new PageResponse<StockResponse>();
            var query = Where(request);
            var list = await query.Paging(request.PageIndex, request.PageSize).ToListAsync();
            response.TotalCount = await query.CountAsync();
            response.PageIndex = request.PageIndex;
            response.PageSize = request.PageSize;
            response.List = _mapper.Map<List<StockResponse>>(list);
            foreach (var model in list)
            {
                var l = response.List.Where(x => x.Id == model.Id).FirstOrDefault();
                if (l != null)
                {
                    foreach (var item in l.BasicQtyLensDetails)
                    {
                        item.Qty = model.StockDetails.Where(x => x.SPH == item.SPH && x.CYL == item.CYL).Select(s => s.BasicQty).FirstOrDefault();
                    }
                }
            }
            return response;
        }
        /// <summary>
        /// 库存管理保存
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        /// <exception cref="ApiException"></exception>
        public async Task Save(StockSaveRequest request)
        {
            if (!await _db.Warehouse.AnyAsync(x => x.Id == request.WarehouseId))
                throw new ApiException("仓库不存在!");
            var lenses = await _db.Lens.Where(x => request.LensIds.Contains(x.Id)).ToListAsync();
            foreach (var lens in lenses)
            {
                if (await _db.Stock.AnyAsync(x => x.WarehouseId == request.WarehouseId && x.LensId == lens.Id))
                    throw new ApiException($"此仓库的镜种{lens.FactoryLensCode}已存在!");
                Stock stock = new()
                {
                    WarehouseId = request.WarehouseId,
                    LensId = lens.Id
                };
                List<StockDetail> details = new();
                for (int sph = lens.MinSPH; sph <= lens.MaxSPH; sph += 25)
                {
                    string degreesType = "-/-";
                    if (sph > 0)
                        degreesType = "+/-";

                    for (int cyl = lens.MinCYL; cyl <= lens.MaxCYL; cyl += 25)
                    {
                        if (details.Any(x => x.SPH == sph && x.CYL == cyl))
                            continue;
                        StockDetail detail = new()
                        {
                            DegreesType = degreesType,
                            SPH = sph,
                            CYL = cyl,
                            Qty = 0,
                            BasicQty = 0
                        };
                        details.Add(detail);
                    }
                }
                stock.StockDetails = details;
                await _db.Stock.AddAsync(stock);
            }
            await _db.SaveChangesAsync();
        }
        /// <summary>
        /// 获取批量仓库镜种列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        /// <exception cref="ApiException"></exception>
        public async Task<List<LensViewResponse>> GetBatchLensDetails(BatchStockLensDetailRequest request)
        {
            var stocks = await _db.Stock.Include(x => x.StockDetails).Include(x => x.Warehouse).Include(x => x.Lens).Where(x => x.WarehouseId == request.WarehouseId && request.LensIds.Contains(x.LensId)).ToListAsync();
            return _mapper.Map<List<LensViewResponse>>(stocks);
        }
        /// <summary>
        /// 获取仓库镜种列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        /// <exception cref="ApiException"></exception>
        public async Task<LensViewResponse> GetStockLensDetails(StockLensDetailRequest request)
        {
            var stock = await _db.Stock.Include(x => x.StockDetails).Include(x => x.Warehouse).Include(x => x.Lens).Where(x => x.WarehouseId == request.WarehouseId && request.LensId == x.LensId).FirstOrDefaultAsync();

            if(stock == null)
                throw new ApiException($"此仓库的镜种库存不存在!");

            return _mapper.Map<LensViewResponse>(stock);
        }
        /// <summary>
        /// 其他出入库
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task BatchAccess(BatchAccessRequest request)
        {
            if (request.File == null)
                throw new ApiException("文件不能为空!");

            var stock = await _db.Stock.Include(x => x.StockDetails).Include(x => x.Warehouse).Include(x => x.Lens).Where(x => x.WarehouseId == request.WarehouseId && x.LensId == request.LensId).FirstOrDefaultAsync();
            if (stock == null)
                throw new ApiException($"此仓库的库存镜种不存在!");

            Stream stream = request.File.OpenReadStream();

            var list = stream.ToLensDetails();

            if (list.Sum(s => s.Qty) <= 0)
                throw new ApiException("XY表总片数为0,请检查!");

            if (!list.InRange(_mapper.Map<LensResponse>(stock.Lens)))
                throw new ApiException("XY表度数超出镜种范围!");

            if (request.Type == (int)StockActionTypeEnum.LeaveStock)
            {
                bool isEnough = !(from a in list
                                  join b in stock!.StockDetails! on new { a.SPH, a.CYL } equals new { b.SPH, b.CYL }
                                  where b.Qty - a.Qty < 0
                                  select b).Any();
                if (!isEnough)
                    throw new ApiException($"超出库存片数,请检查!");

                foreach (var l in list)
                {
                    var model = stock.StockDetails!.Where(x => x.SPH == l.SPH && x.CYL == l.CYL).FirstOrDefault();
                    if (model != null)
                        model.Qty -= l.Qty;
                }
            }
            else
            {
                foreach (var l in list)
                {
                    var model = stock.StockDetails!.Where(x => x.SPH == l.SPH && x.CYL == l.CYL).FirstOrDefault();
                    if (model != null)
                        model.Qty += l.Qty;
                }
            }
            //ActionLogAddRequest actionLogAddRequest = new()
            //{
            //    Type = request.Type,
            //    Status = (int)ActionLogStatusEnum.Finnish,
            //    Reason = request.Reason,
            //    WarehouseId = request.WarehouseId,
            //    LensId = request.LensId,
            //    LensDetails = list,
            //};
            //await _db.SaveChangesAsync();
            //IActionLogService actionLogSvc = _serviceProvider.GetService<IActionLogService>();
            //await actionLogSvc.Add(actionLogAddRequest);
        }
        /// <summary>
        /// 修改基本库存
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task BasicStockModify(BasicStockModifyRequest request)
        {
            if (request.File == null)
                throw new ApiException("文件不能为空!");

            var stocks = await _db.Stock.Include(x => x.StockDetails).Include(x => x.Warehouse).Include(x => x.Lens).Where(x => x.WarehouseId == request.WarehouseId && request.LensIds.Contains(x.LensId)).ToListAsync();
            if (stocks.Count <= 0)
                throw new ApiException($"此仓库的库存镜种不存在!");

            Stream stream = request.File.OpenReadStream();
            var list = stream.ToLensViews();
            foreach (var stock in stocks)
            {
                var details = list.Where(x => x.Warehouse.Code == stock.Warehouse!.Code && (stock.Lens!.SalesLensCode.ToLower().TrimEnd('+').TrimEnd('-') == x.Lens.SalesLensCode.ToLower() || stock.Lens!.SalesLensCode.ToLower().TrimEnd('+').TrimEnd('-') == x.Lens.SalesLensCode.ToLower())).ToList();
                if (details.Count <= 0)
                    throw new ApiException($"未找到导入文件的镜种{stock.Lens!.SalesLensCode}!");
                foreach (var detail in details)
                {
                    foreach (var lensDetail in detail.LensDetails)
                    {
                        var model = stock.StockDetails.Where(x => x.SPH == lensDetail.SPH && x.CYL == lensDetail.CYL).FirstOrDefault();
                        if (model != null)
                            model.BasicQty = lensDetail.Qty;
                    }
                }
            }
            await _db.SaveChangesAsync();
        }
        /// <summary>
        /// 获取库存列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<List<StockResponse>> GetStocks(PageRequest<StockRequest> request)
        {
            var list = await Where(request).ToListAsync();
            return _mapper.Map<List<StockResponse>>(list);
        }
        /// <summary>
        /// 扫描出入库
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        /// <exception cref="ApiException"></exception>
        public async Task ScanBarcodeInOrOutStock(ScanBarcodeInOrOutStockRequest request)
        {
            string sph = "";
            string cyl = "";
            string lensCode = "";
            string degreeType = "-";
            if (!request.BarCode.Contains('-'))
                throw new ApiException("条码格式错误,请检查!");
            if (request.BarCode.Contains('+'))
            {
                string[] strs = request.BarCode.Replace("+", "-").Split('-');
                lensCode = strs[0].Trim();
                sph = "+" + strs[1];
                cyl = strs[2];
                degreeType = "+";
            }
            else
            {
                string[] strs = request.BarCode.Split('-');
                lensCode = strs[0].Trim();
                sph = "-" + strs[1];
                cyl = strs[2];
            }
            var stock = await _db.Stock.Include(x => x.StockDetails).Include(x => x.Warehouse).Include(x => x.Lens).Where(x => x.WarehouseId == request.WarehouseId && (x.Lens!.SalesLensCode == lensCode || x.Lens!.SalesLensCode == lensCode + degreeType)).FirstOrDefaultAsync();
            if (stock == null)
                throw new ApiException($"库存没有{lensCode}镜种,请检查!");
            var stockDetail = stock.StockDetails!.Where(x => x.SPH == sph.ToInt() && x.CYL == cyl.ToInt()).FirstOrDefault();
            if(stockDetail==null)
                throw new ApiException($"度数不在库存镜种{lensCode}范围内,请检查!");

            if (request.Type == (int)StockActionTypeEnum.LeaveStock)
            {
                if (stockDetail.Qty < request.Qty)
                    throw new ApiException($"超出库存片数,请检查!");
                stockDetail.Qty -= request.Qty;
            }
            else
            {
                stockDetail.Qty += request.Qty;
            }
            var lensDetails = _mapper.Map<List<LensDetailResponse>>(stock.StockDetails);
            lensDetails.ForEach(x => x.Qty = x.SPH == sph.ToInt() && x.CYL == cyl.ToInt() ? request.Qty : 0);
            //ActionLogAddRequest actionLogAddRequest = new()
            //{
            //    Type = request.Type,
            //    Status = (int)ActionLogStatusEnum.Finnish,
            //    Reason = request.Reason,
            //    WarehouseId = request.WarehouseId,
            //    LensId = stock.LensId,
            //    LensDetails = lensDetails,
            //};
            //await _db.SaveChangesAsync();
            //IActionLogService actionLogSvc = _serviceProvider.GetService<IActionLogService>()!;
            //await actionLogSvc.Add(actionLogAddRequest);
        }
        /// <summary>
        /// 获取明细
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<List<StockDetailResponse>> GetStockDetails(PageRequest<StockRequest> request)
        {
            var query = Where(request);
            var list = await query.ToListAsync();
            List<StockDetail> stockDetails = new();
            foreach (var detail in list)
            {
                stockDetails.AddRange(detail.StockDetails!);
            }
            return _mapper.Map<List<StockDetailResponse>>(stockDetails);
        }
        /// <summary>
        /// 获取库存数据
        /// </summary>
        /// <returns></returns>
        public async Task<LensViewResponse> GetCurrentStockLensDetail(GetCurrentStockLensDetailRequest request)
        {
            var stock = await _db.Stock.Include(x => x.StockDetails).Include(x => x.Warehouse).Include(x => x.Lens).Where(x => x.WarehouseId == request.WarehouseId && x.LensId == request.LensId).FirstOrDefaultAsync();
            if(stock == null)
                throw new ApiException("此仓库的镜种库存不存在!");
            return _mapper.Map<LensViewResponse>(stock);
        }

        private IQueryable<Stock> Where(PageRequest<StockRequest> request)
        {
            IQueryable<Stock> query = _db.Stock.Include(x => x.StockDetails).Include(x => x.Warehouse).Include(x => x.Lens);
            if (request.Query.WarehouseId != null)
            {
                query = query.Where(x => x.WarehouseId == request.Query.WarehouseId);
            }
            if (request.Query.LensId != null)
            {
                query = query.Where(x => x.LensId == request.Query.LensId);
            }
            return query.OrderBy(x => x.Id);
        }
    }
}
